using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;

namespace Rogue
{
    public enum CellSubLocation
    {
        Center,
        Top,
        Right,
        Bottom,
        Left,
        TopRight,
        BottomRight,
        BottomLeft,
        TopLeft
    }

    public class CellWindow
    {
        #region Public Member Variables
        public Point MapSize
            { get { return new Point(Width, Height); } }

        /// <summary>
        /// This is how many cells wide the window is.
        /// </summary>
        public int Width
            { get { return m_aCellMap.GetLength(0); } }

        /// <summary>
        /// This is how many cells tall the window is.
        /// </summary>
        public int Height
            { get { return m_aCellMap.GetLength(1); } }

        /// <summary>
        /// This is how wide the window is onscreen (in pixels).
        /// </summary>
        public virtual int WindowWidth
            { get { return m_aCellMap.GetLength(0) * m_pCellScreenSize.X; } }

        /// <summary>
        /// This is how tall the window is onscreen (in pixels).
        /// </summary>
        public virtual int WindowHeight
            { get { return m_aCellMap.GetLength(1) * m_pCellScreenSize.X; } }

        /// <summary>
        /// This is how tall and wide the window is onscreen (in pixels).
        /// </summary>
        public Point WindowSize
            { get { return new Point(WindowWidth, WindowHeight); } }

        /// <summary>
        /// This is how wide and tall each cell is in pixels on the screen.
        /// </summary>
        public Point CellScreenSize
            { get { return m_pCellScreenSize; } }

        /// <summary>
        /// This is the bounds of the cellwindow in pixels.
        /// </summary>
        public virtual Rectangle WindowBounds
            { get { return new Rectangle(Position.X, Position.Y, WindowWidth, WindowHeight); } }


        /// <summary>
        /// Returns the cell that the mouse is hovering over
        /// </summary>
        public Point MouseHoverCell
        {
            get
            {
                MouseState mouse = Mouse.GetState();
                Rectangle rWindowBounds = WindowBounds;
                Point pLocalMousePos = new Point(mouse.X - rWindowBounds.Left, mouse.Y - rWindowBounds.Top);
                return new Point(
                    (int)Math.Floor(pLocalMousePos.X / (float)CellScreenSize.X),
                    (int)Math.Floor(pLocalMousePos.Y / (float)CellScreenSize.Y)
                    );
            }
        }

        public Color BorderColor;
        public int BorderOffset;
        
        public bool BorderTop;
        public bool BorderRight;
        public bool BorderBottom;
        public bool BorderLeft;

        public Color BackgroundColor;
        public bool DrawBackground;



        /// <summary>
        /// The top-left position of the window onscreen (in pixels).
        /// </summary>
        public Point Position;

#       endregion

        #region Protected Member Variables
        protected SpriteBatch     m_SpriteBatch;
        protected Texture2D       m_Texture;          
        protected Rectangle[]     m_aCellDefs;               // Cell definitions on the texture sheet
        protected Cell[,]         m_aCellMap;               // The 2D array of cells
        protected Point           m_pCellScreenSize;
        protected LineHelper      m_LineManager;

        protected int m_nFloatingStringCount = 0;
        protected FloatingString[] m_FloatingStrings;

        protected struct FloatingString
        {
            public string s;
            public Vector4 Color;
            public Point Position;
            public Texture2D Tex;
            public Point CharSize;
            public Point CharOffset;
        }
        #endregion

        #region Custom Datatype Definitions
        // CellMap Data
        public struct Cell
        {
            public char UpTile;
            public char ForegroundTile;
            public char BackgroundTile;
            public Color UpColor;
            public Color ForegroundColor;
            public Color BackgroundColor;
            public char OffsetX;
            public char OffsetY;
            public char Saturation;
        }

        // String alignment
        public enum Alignment
        {
            Left,
            Right
        }
        #endregion

        Effect m_greyScale = null;

        #region Constructors
        public CellWindow(Texture2D a_Tex, GraphicsDevice a_Dev, Point a_Pos, Point a_pCellMapSize, Point a_pCellScreenSize ) 
        {
            // Initialization
            m_LineManager = new LineHelper(a_Dev);
            m_SpriteBatch = new SpriteBatch(a_Dev);
            m_Texture = a_Tex;
            Position = a_Pos;
            Reset(a_pCellMapSize.X, a_pCellMapSize.Y);
            m_pCellScreenSize = a_pCellScreenSize;

            m_FloatingStrings = new FloatingString[128];

            m_greyScale = RogueGame.Instance.Content.Load<Effect>("greyScale");

            Viewport viewport = RogueGame.Instance.GraphicsDevice.Viewport;
            Vector2 viewportSize = new Vector2(viewport.Width, viewport.Height);
            m_greyScale.Parameters["ViewportSize"].SetValue(viewportSize);


            // Build cell definitions
            BuildCellDefs();

            // Initialize the buffer
            ClearBuffer();
        }
        #endregion

        #region Init
        /// <summary>
        /// Stores each ASCII character's corresponding coordinates on the curses texture.
        /// </summary>
        private void BuildCellDefs()
        {
            // Get the array of pixel coordinates for each character and store it off
            m_aCellDefs = new Rectangle[256];
            int nTextureCellSizeX = (int)(m_Texture.Width / 16);
            int nTextureCellSizeY = (int)(m_Texture.Height / 16);

            int nCount = 0;
            for (int i = 0; i < 16; i++)
            {
                for (int j = 0; j < 16; j++)
                {
                    m_aCellDefs[nCount] = new Rectangle(j * nTextureCellSizeX, i * nTextureCellSizeY, nTextureCellSizeX, nTextureCellSizeY);
                    nCount++;
                }
            }
        }
        #endregion

        #region Geometry
        /// <summary>
        /// Returns the outline of the cell in relation to the cellmap's local space.
        /// </summary>
        /// <param name="a_X"></param>
        /// <param name="a_Y"></param>
        /// <returns></returns>
        public virtual Rectangle GetLocalCellBounds(int a_X, int a_Y)
        {
            return new Rectangle(
                a_X * m_pCellScreenSize.X, 
                a_Y * m_pCellScreenSize.Y, 
                m_pCellScreenSize.X, 
                m_pCellScreenSize.Y
                );
        }

        /// <summary>
        /// Returns the outline of the cell in screen space.
        /// </summary>
        /// <param name="a_X"></param>
        /// <param name="a_y"></param>
        /// <returns></returns>
        public Rectangle GetScreenCellBounds(int a_X, int a_Y)
        {
            Rectangle rLocalCellBounds = GetLocalCellBounds(a_X, a_Y);
            Rectangle rScreenCellBounds = new Rectangle(
                rLocalCellBounds.Left + Position.X,
                rLocalCellBounds.Top + Position.Y,
                rLocalCellBounds.Width,
                rLocalCellBounds.Height
                );
            return rScreenCellBounds;
        }

        public Rectangle GetScreenCellBounds(Point a_pCell)
        {
            return GetScreenCellBounds(a_pCell.X, a_pCell.Y);
        }



        public Point CellSubLocationToScreenSpace(Point a_pCell, CellSubLocation a_SubLoc)
        {
            return CellSubLocationToScreenSpace(a_pCell.X, a_pCell.Y, a_SubLoc);
        }

        public Point CellSubLocationToScreenSpace(int a_X, int a_Y, CellSubLocation a_SubLoc)
        {
            Rectangle rScreenCellOutline = GetScreenCellBounds(a_X, a_Y);

            int nHorizontalOffset = (int)Math.Floor((float)(rScreenCellOutline.Width / 2));
            int nVerticalOffset = (int)Math.Floor((float)(rScreenCellOutline.Height / 2));

            switch (a_SubLoc)
            {
                case CellSubLocation.TopLeft:
                    return new Point(rScreenCellOutline.Left, rScreenCellOutline.Top);

                case CellSubLocation.Top:
                    return new Point(rScreenCellOutline.Left + nHorizontalOffset, rScreenCellOutline.Top);

                case CellSubLocation.TopRight:
                    return new Point(rScreenCellOutline.Right, rScreenCellOutline.Top);

                case CellSubLocation.Right:
                    return new Point(rScreenCellOutline.Right, rScreenCellOutline.Top + nVerticalOffset);

                case CellSubLocation.BottomRight:
                    return new Point(rScreenCellOutline.Right, rScreenCellOutline.Bottom);

                case CellSubLocation.Bottom:
                    return new Point(rScreenCellOutline.Left + nHorizontalOffset, rScreenCellOutline.Bottom);

                case CellSubLocation.BottomLeft:
                    return new Point(rScreenCellOutline.Left, rScreenCellOutline.Bottom);

                case CellSubLocation.Left:
                    return new Point(rScreenCellOutline.Left, rScreenCellOutline.Top + nVerticalOffset);
                
                case CellSubLocation.Center:
                    return new Point(rScreenCellOutline.Left + nHorizontalOffset, rScreenCellOutline.Top + nVerticalOffset);

                default:
                    return new Point(0, 0);
            }
        }
        #endregion

        #region Drawing Characters
        /// <summary>
        /// Puts a white character on the glyphbuffer at the coordinates you specify
        /// </summary>
        public void PutChar(char c, int a_X, int a_Y)
        {
            PutChar(c, a_X, a_Y, Color.White);
        }

        public void PutChar(char c, int a_X, int a_Y, Vector4 a_Color)
        {
            PutChar(c, a_X, a_Y, a_Color, Vector4.Zero);
        }

        public void PutChar(char c, int a_X, int a_Y, Color a_Color)
        {
            PutChar(c, a_X, a_Y, a_Color.ToVector4(), Vector4.Zero);
        }

        public void PutChar(char c, int a_X, int a_Y, Vector4 a_ForegroundColor, Vector4 a_BackgroundColor)
        {
            PutChar(c,          new Color(a_ForegroundColor),
                    (char)255,  new Color(a_BackgroundColor),
                    (char)0,    new Color(0, 0, 0, 0),
                    a_X, a_Y, 
                    0, 0);
        }

        public void PutChar(char a_cFore, Color a_ForeColor, char a_cBack, Color a_BackColor, Point a_pDest)
        {
            PutChar(a_cFore, a_ForeColor,
                    a_cBack, a_BackColor,
                    '\0', Color.TransparentBlack,
                    a_pDest.X, a_pDest.Y, 0, 0);
        }

        public void PutChar(char a_cFore, Color a_ForeColor,
                            char a_cBack, Color a_BackColor,
                            char a_Up, Color a_UpColor,
                            int a_X, int a_Y,
                            int o_X, int o_Y)
        {
            PutChar(a_cFore, a_ForeColor,
                    a_cBack, a_BackColor,
                    a_Up, a_UpColor,
                    a_X, a_Y, 
                    o_X, o_Y, 
                    1.0f);
        }

        public void PutChar(char a_cFore, Color a_ForeColor, 
                            char a_cBack, Color a_BackColor, 
                            char a_Up, Color a_UpColor,
                            int a_X, int a_Y,
                            int o_X, int o_Y,
                            float a_Saturation)
        {

            if (a_X < 0)
                return;

            if (a_Y < 0)
                return;

            if (a_X >= Width)
                return;
            
            if (a_Y >= Height)
                return;

            m_aCellMap[a_X, a_Y].ForegroundTile = a_cFore;
            m_aCellMap[a_X, a_Y].ForegroundColor = a_ForeColor;
            m_aCellMap[a_X, a_Y].BackgroundTile = a_cBack;
            m_aCellMap[a_X, a_Y].BackgroundColor = a_BackColor;
            m_aCellMap[a_X, a_Y].UpTile = a_Up;
            m_aCellMap[a_X, a_Y].UpColor = a_UpColor;
            m_aCellMap[a_X, a_Y].OffsetX = (char) o_X;
            m_aCellMap[a_X, a_Y].OffsetY = (char) o_Y;
            m_aCellMap[a_X, a_Y].Saturation = (char)(255.0f * a_Saturation);
        }

        public void PutForegroundChar(char a_cFore, Color a_ForeColor, int a_X, int a_Y)
        {
            if (a_X < 0)
                return;

            if (a_Y < 0)
                return;

            if (a_X >= Width)
                return;

            if (a_Y >= Height)
                return;

            m_aCellMap[a_X, a_Y].ForegroundTile = a_cFore;
            m_aCellMap[a_X, a_Y].ForegroundColor = a_ForeColor;
        }
        #endregion

        #region Drawing Strings
        /// <summary>
        /// Draw a white string at a specified location. It will be left-aligned.
        /// </summary>
        /// <param name="a_sString"></param>
        /// <param name="a_X"></param>
        /// <param name="a_Y"></param>
        public void PutString(string a_sString, int a_X, int a_Y)
        {
            PutString(a_sString, a_X, a_Y, Color.White, CellWindow.Alignment.Left);
        }

        /// <summary>
        /// Draw a string with a specified color and location. It will be left-aligned.
        /// </summary>
        public void PutString(string a_sString, int a_X, int a_Y, Color a_Color)
        {
            PutString(a_sString, a_X, a_Y, a_Color, CellWindow.Alignment.Left);
        }


        /// <summary>
        /// Draws a string with a specified color, location, and alignment.
        /// </summary>
        public void PutString(string a_sString, int a_X, int a_Y, Color a_Color, Alignment a_Align)
        {
            int nOffset = 0;

            if (a_sString != null)
            {
                if (a_Align == Alignment.Right)
                {
                    for (int i = 0; i < a_sString.Length; i++)
                    {
                        PutChar(a_sString[i], (a_X - (a_sString.Length - 1)) + i, a_Y, a_Color);
                    }
                }
                else
                {
                    for (int i = 0; i < a_sString.Length; i++)
                    {
                        PutChar(a_sString[i], (a_X + nOffset) + i, a_Y, a_Color);
                    }
                }
            }
        }

        public void PutFloatingString(string a_sString, Point a_pDest, Color a_Color, 
            Texture2D a_Texture, Point a_CharSize, Point a_CharOffset)
        {
            FloatingString FloatingString = new FloatingString();
            FloatingString.s = a_sString;
            FloatingString.Position = a_pDest;
            FloatingString.Color = a_Color.ToVector4();
            FloatingString.Tex = a_Texture != null ? a_Texture : m_Texture;
            FloatingString.CharSize = a_CharSize;
            FloatingString.CharOffset = a_CharOffset;
            m_FloatingStrings[m_nFloatingStringCount] = FloatingString;
            m_nFloatingStringCount++;
        }

        public virtual void PutFloatingString(string a_sString, Point a_pDest, Color a_Color)
        {
            PutFloatingString(a_sString, a_pDest, a_Color, null, m_pCellScreenSize, Point.Zero);
        }

        #endregion

        #region Clearing the buffer
        /// <summary>
        /// Initializes the console to the specified size.
        /// </summary>
        public void Reset(int a_nMapSizeX, int a_nMapSizeY, Point a_pCellScreenSize)
        {
            m_aCellMap = null;
            m_aCellMap = new Cell[a_nMapSizeX, a_nMapSizeY];
            m_pCellScreenSize = a_pCellScreenSize;
 
        }

        public void Reset(int a_nMapSizeX, int a_nMapSizeY)
        {
            Reset(a_nMapSizeX, a_nMapSizeY, m_pCellScreenSize);
        }
        /// <summary>
        /// Clear the entire cellmap with a white ' ' character.
        /// </summary>
        public void ClearBuffer()
        {
            ClearBuffer(' ', Color.White);
        }

        /// <summary>
        /// Clear the cellmap, using a custom character and color.
        /// </summary>
        /// <param name="a_c">Character</param>
        /// <param name="a_color">Color</param>
        public void ClearBuffer(char a_c, Color a_color)
        {
            for (int y = 0; y < Height; y++)
            {
                for (int x = 0; x < Width; x++)
                {
                    m_aCellMap[x, y].ForegroundTile = a_c;
                    m_aCellMap[x, y].ForegroundColor = a_color;
                    m_aCellMap[x, y].BackgroundColor = new Color(0, 0, 0, 0);
                    m_aCellMap[x, y].UpColor = new Color(0, 0, 0, 0);
                }
            }
        }

        public void ClearBuffer(char a_c, Vector4 a_vColor)
        {
            ClearBuffer(a_c, new Color(a_vColor));
        }
        #endregion

        #region Drawing Lines
        /// <summary>
        /// Puts a 2D line on the screen.
        /// </summary>
        /// <param name="a_PointA"></param>
        /// <param name="a_PointB"></param>
        /// <param name="a_Color"></param>
        public void DrawLine(Point a_PointA, Point a_PointB, Color a_Color)
        {
            m_LineManager.AddLine(a_PointA, a_PointB, a_Color);
        }

        /// <summary>
        /// Puts a 2D line on the screen that has a black shadow underneath.
        /// </summary>
        /// <param name="a_PointA"></param>
        /// <param name="a_PointB"></param>
        /// <param name="a_Color"></param>
        public void DrawShadowedLine(Point a_PointA, Point a_PointB, Color a_Color)
        {
            m_LineManager.AddLineWithShadow(a_PointA, a_PointB, a_Color);
        }

        public void DrawLine(Point a_CellA, CellSubLocation a_SubLocA, Point a_CellB, CellSubLocation a_SubLocB, Color a_Color)
        {
            Point pScreenCellA = CellSubLocationToScreenSpace(a_CellA.X, a_CellA.Y, a_SubLocA);
            Point pScreenCellB = CellSubLocationToScreenSpace(a_CellB.X, a_CellB.Y, a_SubLocB);

            DrawLine(pScreenCellA, pScreenCellB, a_Color);
        }

        public void DrawBorder()
        {
            Rectangle rBounds = WindowBounds;
            if (BorderTop)
                DrawLine(new Point(rBounds.Left, rBounds.Top), new Point(rBounds.Right, rBounds.Top), BorderColor);   
            if (BorderRight)
                DrawLine(new Point(rBounds.Right, rBounds.Top), new Point(rBounds.Right, rBounds.Bottom), BorderColor);
            if (BorderBottom)
                DrawLine(new Point(rBounds.Right, rBounds.Bottom), new Point(rBounds.Left, rBounds.Bottom), BorderColor);
            if (BorderLeft)
                DrawLine(new Point(rBounds.Left, rBounds.Bottom), new Point(rBounds.Left, rBounds.Top), BorderColor);
        }

        public virtual void DrawCellOutline(int a_X, int a_Y, Color a_Color)
        {
            DrawCellOutline(new Point(a_X, a_Y), a_Color);
        }

        public virtual void DrawCellOutline(Point a_pCoord, Color a_Color)
        {
            Rectangle rScreenCellOutline = GetScreenCellBounds(a_pCoord.X, a_pCoord.Y);
            DrawRectOutline(rScreenCellOutline, a_Color);
        }

        public void DrawRectOutline(Rectangle rScreenCellOutline, Color a_Color)
        {
            Point TopLeft = new Point(rScreenCellOutline.Left, rScreenCellOutline.Top);
            Point TopRight = new Point(rScreenCellOutline.Right, rScreenCellOutline.Top);
            Point BottomRight = new Point(rScreenCellOutline.Right, rScreenCellOutline.Bottom);
            Point BottomLeft = new Point(rScreenCellOutline.Left, rScreenCellOutline.Bottom);

            DrawLine(TopLeft, TopRight, a_Color);
            DrawLine(TopRight, BottomRight, a_Color);
            DrawLine(BottomRight, BottomLeft, a_Color);
            DrawLine(BottomLeft, TopLeft, a_Color);
        }

        #endregion

        #region Setting Colors

        public void SetForegroundColor(int a_X, int a_Y, Color a_NewColor)
        {
            m_aCellMap[a_X, a_Y].ForegroundColor = a_NewColor;
        }

        public void SetForegroundColor(int a_X, int a_Y, Vector4 a_vNewColor)
        {
            m_aCellMap[a_X, a_Y].ForegroundColor = new Color(a_vNewColor);
        }

        public void SetAllForegroundColor(Vector4 a_NewColor)
        {
            SetAllForegroundColor(new Color(a_NewColor));
        }

        public void SetAllForegroundColor(Color a_NewColor)
        {
            for (int y = 0; y < Height; y++)
            {
                for (int x = 0; x < Width; x++)
                {
                    m_aCellMap[x, y].ForegroundColor = a_NewColor;
                }
            }
        }

        public void SetBackgroundColor(int a_X, int a_Y, Color a_NewColor)
        {
            SetBackgroundColor(a_X, a_Y, a_NewColor.ToVector4());
        }

        public void SetBackgroundColor(int a_X, int a_Y, Vector4 a_nNewColor)
        {
            m_aCellMap[a_X, a_Y].BackgroundColor = new Color(a_nNewColor);
        }

        public void SetAllBackgroundColor(Color a_NewColor)
        {
            for (int y = 0; y < Height; y++)
            {
                for (int x = 0; x < Width; x++)
                {
                    m_aCellMap[x,y].ForegroundColor = a_NewColor;
                }
            }
        }

        public void SetAllBackgroundColor(Vector4 a_vNewColor)
        {
            SetAllBackgroundColor(new Color(a_vNewColor));
        }
        #endregion

        public virtual void Update(GameTime dt)
        {
            // Nothing for now
        }

        #region Rendering

        public void DrawSolidBG()
        {
            // this is kind of retarded :( Draw the background with a spritebatch call...
            m_SpriteBatch.Begin(SpriteBlendMode.None, SpriteSortMode.Immediate, SaveStateMode.None);
            Rectangle innerRect = WindowBounds;
            innerRect.X += 1;
            innerRect.Y += 1;
            innerRect.Width -= 1;
            innerRect.Height -= 1;
            m_SpriteBatch.Draw(m_Texture, innerRect, BackgroundColor);
            m_SpriteBatch.End();
        }

        public virtual void Draw(GraphicsDevice a_Device)
        {
            if (DrawBackground)
                DrawSolidBG();  // unblended - depends on render order only, so that window Render call order 

            m_SpriteBatch.Begin(SpriteBlendMode.AlphaBlend, SpriteSortMode.Immediate, SaveStateMode.None);

            if (this == TerrainWindow.Instance)
            {
                m_greyScale.Begin();
                m_greyScale.CurrentTechnique.Passes[0].Begin();
            }

            m_SpriteBatch.GraphicsDevice.SamplerStates[0].MagFilter = TextureFilter.Point;
            RenderCells();
            RenderFloatingStrings();

            if (this == TerrainWindow.Instance)
            {
                m_greyScale.CurrentTechnique.Passes[0].End();
                m_greyScale.End();
            }

            m_SpriteBatch.End();

            ClearBuffer();                  // Clear the cell map
            DrawBorder();                   // Draw line borders
            m_LineManager.Draw(a_Device);   // LineManager draws
        }

        public virtual void RenderCells()
        {
            for (int y = 0; y < Height; y++)
            {
                for (int x = 0; x < Width; x++)
                {
                    Rectangle dest = GetRenderDest(x, y);

                    if (m_aCellMap[x, y].BackgroundColor.A > 0)
                    {
                        m_SpriteBatch.Draw(m_Texture, dest, m_aCellDefs[(int)m_aCellMap[x, y].BackgroundTile], m_aCellMap[x, y].BackgroundColor,
                            0, Vector2.Zero, SpriteEffects.None,
                            m_aCellMap[x, y].Saturation / 255.0f);
                    }

                    m_SpriteBatch.Draw(m_Texture, dest, GetRenderSource(x, y), m_aCellMap[x, y].ForegroundColor, 
                            0, Vector2.Zero, SpriteEffects.None,
                            m_aCellMap[x, y].Saturation / 255.0f);

                    int upTile = (int)m_aCellMap[x, y].UpTile;
                    if (m_aCellMap[x, y].UpColor.A > 0 && upTile > 0)
                    {
                        m_SpriteBatch.Draw(m_Texture, dest, m_aCellDefs[upTile], m_aCellMap[x, y].UpColor, 
                            0, Vector2.Zero, SpriteEffects.None,
                            m_aCellMap[x, y].Saturation / 255.0f);
                    }
                }
            }
        }

        public virtual void RenderFloatingStrings()
        {
            for (int i = 0; i < m_nFloatingStringCount; i++)
            {
                for (int j = 0; j < m_FloatingStrings[i].s.Length; j++)
                {
                    int nOffsetX = j * (m_FloatingStrings[i].CharSize.X + m_FloatingStrings[i].CharOffset.X);

                    char c = m_FloatingStrings[i].s[j];
                    m_SpriteBatch.Draw(
                        m_Texture,
                        new Vector2(m_FloatingStrings[i].Position.X + nOffsetX, m_FloatingStrings[i].Position.Y),
                        m_aCellDefs[(int)c],
                        new Color(m_FloatingStrings[i].Color)
                        );
                }
            }
            m_nFloatingStringCount = 0;
        }

        public virtual Rectangle GetRenderSource(int a_X, int a_Y)
        {
            return m_aCellDefs[(int)m_aCellMap[a_X, a_Y].ForegroundTile];
        }

        public virtual Rectangle GetRenderDest(int a_X, int a_Y)
        {
            return new Rectangle(
                (a_X * m_pCellScreenSize.X) + Position.X,
                (a_Y * m_pCellScreenSize.Y) + Position.Y,
                m_pCellScreenSize.X,
                m_pCellScreenSize.Y
                ); 
        }
        #endregion

    }
}
